/**
 * @author ZyElite
 * @time 2022-07-27
 */

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#include "xlog.h"

#ifdef __ANDROID__

#include <android/log.h>

#define ANDROID_LOG_TAG "xlog"

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, ANDROID_LOG_TAG, __VA_ARGS__)

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, ANDROID_LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, ANDROID_LOG_TAG, __VA_ARGS__)

#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, ANDROID_LOG_TAG, __VA_ARGS__)

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, ANDROID_LOG_TAG, __VA_ARGS__)

#endif

static const char *loginfo[] = {
        [ERROR] = "ERROR",
        [WARN]  = "WARN",
        [DEBUG] = "DEBUG",
        [INFO]  = "INFO",
        [VERBOSE] = "VERBOSE"
};

static void get_timestamp(char *buffer) {
    time_t t;
    struct tm *p;
    struct timeval tv;
    int len;
    int millsec;

    t = time(NULL);
    p = localtime(&t);

    gettimeofday(&tv, NULL);
    millsec = (int) (tv.tv_usec / 1000);

    len = snprintf(buffer, 32, "[%04d-%02d-%02d %02d:%02d:%02d:%03d] ",
                   p->tm_year + 1900, p->tm_mon + 1,
                   p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, millsec);

    buffer[len] = '\0';
}

void xlog(const char *filename, int line, enum Level level, const char *fmt, ...) {

    va_list arg_list;
    char buf[1024];
    memset(buf, 0, 1024);
    va_start(arg_list, fmt);
    vsnprintf(buf, 1024, fmt, arg_list);

#ifndef __ANDROID__
    char time[32] = {0};
    get_timestamp(time);
#endif

    const char *tmp = strrchr(filename, '/');
    if (!tmp) tmp = filename;
    else tmp++;


    switch (level) {
        case DEBUG:
#ifdef __ANDROID__
            LOGD("[%s:%d] %s", tmp, line, buf);
#else
            printf("\033[1;32m%s[%s] [%s:%d] %s\n\033[0m", time, loginfo[level], tmp, line, buf);
#endif
            break;
        case INFO:
#ifdef __ANDROID__
            LOGI("[%s:%d] %s", tmp, line, buf);
#else
            printf("\033[1;34m%s[%s] [%s:%d] %s\n\033[0m", time, loginfo[level], tmp, line, buf);
#endif
            break;
        case ERROR:
#ifdef __ANDROID__
            LOGE("[%s:%d] %s", tmp, line, buf);
#else
            printf("\033[1;31m%s[%s] [%s:%d] %s\n\033[0m", time, s_loginfo[level], tmp, line, buf);
#endif
            break;
        case WARN:
#ifdef __ANDROID__
            LOGW("[%s:%d] %s", tmp, line, buf);
#else
            printf("\033[1;33m%s[%s] [%s:%d] %s\n\033[0m", time, loginfo[level], tmp, line, buf);
#endif

            break;
        case VERBOSE:
#ifdef __ANDROID__
            LOGV("[%s:%d] %s", tmp, line, buf);
#else
            printf("\033[1;34m%s[%s] [%s:%d] %s\n\033[0m", time, loginfo[level], tmp, line, buf);
#endif
            break;

    }
    va_end(arg_list);
}